#include <map>
#include <list>
#include <memory>
#include <string>
#include <iostream>
#include "stl_new_functions.h"

class CStlNewFunctions::Test
{
public:
    Test(size_t a, size_t b, size_t c);
    ~Test();
    Test(const Test& rhs);

private:
    size_t m_a;
    size_t m_b;
    size_t m_c;
};

CStlNewFunctions::Test::Test(size_t a, size_t b, size_t c)
{
    m_a = a;
    m_b = b;
    m_c = c;
    std::cout << "Test constructor." << std::endl;
}

CStlNewFunctions::Test::~Test()
{
    std::cout << "Test destructor." << std::endl;
}

CStlNewFunctions::Test::Test(const CStlNewFunctions::Test& rhs)
{
    if (this == &rhs) {
        return;
    }

    m_a = rhs.m_a;
    m_b = rhs.m_b;
    m_c = rhs.m_c;
    std::cout << "Test copy-constructor." << std::endl;
}

class CStlNewFunctions::ChatDialog
{
public:
    ChatDialog(size_t userid = 0)
    {
        std::cout << "ChatDialog constructor." << std::endl;
    }
    ~ChatDialog()
    {
        std::cout << "ChatDialog destructor." << std::endl;
    }

public:
    void activate() {}
};

void CStlNewFunctions::emplaceBack()
{
    std::cout << ">>>begin " << __FUNCTION__ << std::endl;
    std::list<Test> collections;
    for (size_t i = 0; i < 10; ++i) {
        Test t(1 * i, 2 * i, 3 * i);
        collections.push_back(t);
    }
    std::cout << "===middle " << __FUNCTION__ << std::endl;
    std::list<Test> collections2;
    for (size_t i = 0; i < 10; ++i) {
        collections.emplace_back(1 * i, 2 * i, 3 * i);
    }
    std::cout << "<<<end " << __FUNCTION__ << std::endl;
}

void CStlNewFunctions::tryEmplace()
{
    std::map<int64_t, ChatDialog*> chatDialogs;
    auto fr = [&](int64_t userid) {
        auto targetChatDialog = chatDialogs.find(userid);
        if (targetChatDialog == chatDialogs.end()) {
            ChatDialog* chatDialog = new ChatDialog;
            chatDialogs.insert(std::pair<int64_t, ChatDialog*>(userid, chatDialog));
            chatDialog->activate();
        } else {
            targetChatDialog->second->activate();
        }
    };
    fr(906106643L);
    fr(906106644L);
    fr(906106643L);
}

void CStlNewFunctions::tryEmplace2()
{
#if 0
    std::map<int64_t, ChatDialog*> chatDialogs;
    auto fr = [&](int64_t userid) {
        auto[iter, inserted] = chatDialogs.try_emplace(userid);
        if (inserted) {
            iter->second = new ChatDialog;
        }

        iter->second->activate();
    };
    fr(906106643L);
    fr(906106644L);
    fr(906106643L);
#endif
}

void CStlNewFunctions::tryEmplace3()
{
#if 0
    std::map<int64_t, std::unique_ptr<ChatDialog>> chatDialogs;
    auto fr = [&](int64_t userid) {
        auto spChatDialog = std::make_unique<ChatDialog>();
        auto[iter, inserted] = chatDialogs.try_emplace(userid, std::move(spChatDialog));
        iter->second->activate();
    };
    fr(906106643L);
    fr(906106644L);
    fr(906106643L);
#endif
}

void CStlNewFunctions::tryEmplace4()
{
#if 0
    std::map<int64_t, std::unique_ptr<ChatDialog>> chatDialogs;
    auto fr = [&](int64_t userid) {
        auto[iter, inserted] = chatDialogs.try_emplace(userid, nullptr);
        if (inserted) {
            iter->second = std::make_unique<ChatDialog>();
        }
        iter->second->activate();
    };
    fr(906106643L);
    fr(906106644L);
    fr(906106643L);
#endif
}

void CStlNewFunctions::tryEmplace5()
{
#if 0

    std::map<int64_t, ChatDialog> chatDialogs;
    auto fr = [&](int64_t userid) {
        auto[iter, inserted] = chatDialogs.try_emplace(userid, userid);
        iter->second.activate();
    };
    fr(906106643L);
    fr(906106644L);
    fr(906106643L);

#endif
}

void CStlNewFunctions::insertOrAssign()
{
#if 0
    std::map<std::string, int> mapUsersAge{ {"Alex", 45}, {"John", 25} };
    mapUsersAge.insert_or_assign("Tom", 26);
    mapUsersAge.insert_or_assign("Alex", 27);

    for (const auto& [name, age] : mapUsersAge) {
        std::cout << name << age << std::endl;
    }
#endif
}